/*
Copyright (C) 2003-2004 The Pentagram Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

// istring.h -- case insensitive stl strings

#ifndef ISTRING_H
#define	ISTRING_H

#include <string>
#include "common_types.h"

namespace Pentagram {

int strcasecmp (const char *s1, const char *s2);
int strncasecmp (const char *s1, const char *s2, uint32 length);

#ifndef UNDER_CE

//! STL char_traits for case insensitive comparisons
struct ichar_traits : public std::char_traits<char>
{
	//! Case insensitive check for 2 chars being equal
	static bool eq(const char_type & c1, const char_type & c2);

	//! Case insensitive check for the first char being less
	//! than the second char
	static bool lt(const char_type & c1, const char_type & c2);

	//! Case insensitive comparison for 2 c_strings - based off Q_strncasecmp
	static int compare(const char_type * s1, const char_type * s2, size_t length);
};

template<class _Elem,
	class _Traits = std::char_traits<_Elem>,
	class _Ax = std::allocator<_Elem> >
	class pent_string
		: public std::basic_string<_Elem, _Traits, _Ax>
	{	// null-terminated transparent array of elements
public:
	typedef pent_string<_Elem, _Traits, _Ax> _Myt;
	typedef std::basic_string<_Elem, _Traits, _Ax> _Mybase;
	typedef _Ax _Alloc;
	typedef typename _Alloc::size_type size_type;
	typedef typename _Alloc::difference_type difference_type;
	typedef typename _Alloc::pointer _Tptr;
	typedef typename _Alloc::const_pointer _Ctptr;
	typedef _Tptr pointer;
	typedef _Ctptr const_pointer;
	typedef typename _Alloc::reference reference;
	typedef typename _Alloc::const_reference const_reference;
	typedef typename _Alloc::value_type value_type;

	typedef ichar_traits traits_type;

	pent_string() 
		: _Mybase()
		{
		}

	explicit pent_string(const _Alloc& _Al)
		: _Mybase(_Al)
		{
		}

	pent_string(const _Mybase& _Right)
		: _Mybase(_Right)
		{	// construct by copying _Right
		}

	pent_string(const _Mybase& _Right, size_type _Roff,
		size_type _Count = _Mybase::npos)
		: _Mybase(_Right, _Roff, _Count)
		{	// construct from _Right [_Roff, _Roff + _Count)
		}

	pent_string(const _Mybase& _Right, size_type _Roff, size_type _Count,
		const _Alloc& _Al)
		: _Mybase(_Right, _Roff, _Count, _Al)
		{	// construct from _Right [_Roff, _Roff + _Count) with allocator
		}

	pent_string(const _Elem *_Ptr, size_type _Count)
		: _Mybase(_Ptr, _Count)
		{	// construct from [_Ptr, _Ptr + _Count)
		}

	pent_string(const _Elem *_Ptr, size_type _Count, const _Alloc& _Al)
		: _Mybase(_Ptr, _Count, _Al)
		{	// construct from [_Ptr, _Ptr + _Count) with allocator
		}

	pent_string(const _Elem *_Ptr)
		: _Mybase(_Ptr)
		{	// construct from [_Ptr, <null>)
		}

	pent_string(const _Elem *_Ptr, const _Alloc& _Al)
		: _Mybase(_Ptr, _Al)
		{	// construct from [_Ptr, <null>) with allocator
		}

	pent_string(size_type _Count, _Elem _Ch)
		: _Mybase(_Count, _Ch)
		{	// construct from _Count * _Ch
		}

	pent_string(size_type _Count, _Elem _Ch, const _Alloc& _Al)
		: _Mybase(_Count, _Ch, _Al)
		{	// construct from _Count * _Ch with allocator
		}

	template<class _It>
		pent_string(_It _First, _It _Last)
		: _Mybase(_First, _Last)
		{	// construct from [_First, _Last)
		}

	template<class _It>
		pent_string(_It _First, _It _Last, const _Alloc& _Al)
		: _Mybase(_First, _Last, _Al)
		{	// construct from [_First, _Last) with allocator
		}

	//
	// Overloaded operators (will return the correct type)
	//

	_Myt& operator=(const _Myt& _Right)
		{	// assign _Right
		assign(_Right);
		return (*this);
		}

	_Myt& operator=(const _Elem *_Ptr)
		{	// assign [_Ptr, <null>)
		assign(_Ptr);
		return (*this);
		}

	_Myt& operator=(_Elem _Ch)
		{	// assign 1 * _Ch
		assign(1, _Ch);
		return (*this);
		}

	_Myt& operator+=(const _Myt& _Right)
		{	// append _Right
		append(_Right);
		return (*this);
		}

	_Myt& operator+=(const _Elem *_Ptr)
		{	// append [_Ptr, <null>)
		append(_Ptr);
		return (*this);
		}

	_Myt& operator+=(_Elem _Ch)
		{	// append 1 * _Ch
		append(static_cast<size_type>(1), _Ch);
		return (*this);
		}

	// New case insensitive compare functions

	int compare(const _Mybase& _Right) const
		{	// compare [0, _Mysize) with _Right
		return (compare(0, this->size(), _Right.data(), _Right.size()));
		}

	int compare(size_type _Off, size_type _N0,
		const _Mybase& _Right) const
		{	// compare [_Off, _Off + _N0) with _Right
		return (compare(_Off, _N0, _Right, 0, _Mybase::npos));
		}

	int compare(size_type _Off, size_type _N0, const _Myt& _Right,
		size_type _Roff, size_type _Count) const
		{	// compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
		if (_Right.size() < _Roff)
			return 0; //_String_base::_Xran();	// _Off off end
		if (_Right.size() - _Roff < _Count)
			_Count = _Right.size() - _Roff;	// trim _Count to size
		return (compare(_Off, _N0, _Right.data() + _Roff, _Count));
		}

	int compare(const _Elem *_Ptr) const
		{	// compare [0, _Mysize) with [_Ptr, <null>)
		return (compare(0, this->size(), _Ptr, _Traits::length(_Ptr)));
		}

	int compare(size_type _Off, size_type _N0, const _Elem *_Ptr) const
		{	// compare [_Off, _Off + _N0) with [_Ptr, <null>)
		return (compare(_Off, _N0, _Ptr, _Traits::length(_Ptr)));
		}

	int compare(size_type _Off, size_type _N0, const _Elem *_Ptr,
		size_type _Count) const
		{	// compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count)
		if (this->size() < _Off)
			return 0; //_String_base::_Xran();	// _Off off end
		if (this->size() - _Off < _N0)
			_N0 = this->size() - _Off;	// trim _N0 to size

		size_type _Ans = _N0 == 0 ? 0
			: ichar_traits::compare(this->data() + _Off, _Ptr,
				_N0 < _Count ? _N0 : _Count);
		return (_Ans != 0 ? static_cast<int>(_Ans) : _N0 < _Count ? -1
			: _N0 == _Count ? 0 : +1);
		}
	};

//! STL case insensitve string
//template pent_string<char>;
typedef pent_string<char> istring;

inline pent_string<char> operator+(
		const pent_string<char> & _Left,
		const pent_string<char> & _Right)
	{	// return string + string
	return (pent_string<char>(_Left) += _Right);
	}

inline pent_string<char> operator+(
		const pent_string<char> & _Left,
		const std::basic_string<char>& _Right)
	{	// return string + string
	return (pent_string<char>(_Left) += _Right);
	}

inline pent_string<char> operator+(
		const std::basic_string<char>& _Left,
		const pent_string<char> & _Right)
	{	// return string + string
	return (pent_string<char>(_Left) += _Right);
	}

inline pent_string<char> operator+(
		const char *_Left,
		const pent_string<char>& _Right)
	{	// return NTCS + string
	return (pent_string<char>(_Left) += _Right);
	}

inline pent_string<char> operator+(
		const char _Left,
		const pent_string<char>& _Right)
	{	// return character + string
	return (pent_string<char>(1, _Left) += _Right);
	}

inline pent_string<char> operator+(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// return string + NTCS
	return (pent_string<char>(_Left) += _Right);
	}

inline pent_string<char> operator+(
		const pent_string<char>& _Left,
		const char _Right)
	{	// return string + character
	return (pent_string<char>(_Left) += _Right);
	}


inline bool operator==(
		const pent_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test for string equality
	return (_Left.compare(_Right) == 0);
	}

inline bool operator==(
		const pent_string<char>& _Left,
		const std::basic_string<char>& _Right)
	{	// test for string equality
	return (_Left.compare(_Right) == 0);
	}

inline bool operator==(
		const std::basic_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test for string equality
	return (_Right.compare(_Left) == 0);
	}

inline bool operator==(
		const char * _Left,
		const pent_string<char>& _Right)
	{	// test for NTCS vs. string equality
	return (_Right.compare(_Left) == 0);
	}

inline bool operator==(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// test for string vs. NTCS equality
	return (_Left.compare(_Right) == 0);
	}

inline bool operator!=(
		const pent_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test for string inequality
	return (!(_Left == _Right));
	}

inline bool operator!=(
		const pent_string<char>& _Left,
		const std::basic_string<char>& _Right)
	{	// test for string inequality
	return (!(_Left == _Right));
	}

inline bool operator!=(
		const std::basic_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test for string inequality
	return (!(_Left == _Right));
	}

inline bool operator!=(
		const char *_Left,
		const pent_string<char>& _Right)
	{	// test for NTCS vs. string inequality
	return (!(_Left == _Right));
	}

inline bool operator!=(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// test for string vs. NTCS inequality
	return (!(_Left == _Right));
	}



inline bool operator<(
		const pent_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string < string
	return (_Left.compare(_Right) < 0);
	}

inline bool operator<(
		const pent_string<char>& _Left,
		const std::basic_string<char>& _Right)
	{	// test if string < string
	return (_Left.compare(_Right) < 0);
	}

inline bool operator<(
		const std::basic_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string < string
	return (_Right.compare(_Left) > 0);
	}

inline bool operator<(
		const char * _Left,
		const pent_string<char>& _Right)
	{	// test if NTCS < string
	return (_Right.compare(_Left) > 0);
	}

inline bool operator<(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// test if string < NTCS
	return (_Left.compare(_Right) < 0);
	}



inline bool operator>(
		const pent_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string > string
	return (_Right < _Left);
	}

inline bool operator>(
		const pent_string<char>& _Left,
		const std::basic_string<char>& _Right)
	{	// test if string > string
	return (_Right < _Left);
	}

inline bool operator>(
		const std::basic_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string > string
	return (_Right < _Left);
	}

inline bool operator>(
		const char * _Left,
		const pent_string<char>& _Right)
	{	// test if NTCS > string
	return (_Right < _Left);
	}

inline bool operator>(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// test if string > NTCS
	return (_Right < _Left);
	}


inline bool operator<=(
		const pent_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string <= string
	return (!(_Right < _Left));
	}

inline bool operator<=(
		const pent_string<char>& _Left,
		const std::basic_string<char>& _Right)
	{	// test if string <= string
	return (!(_Right < _Left));
	}

inline bool operator<=(
		const std::basic_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string <= string
	return (!(_Right < _Left));
	}

inline bool operator<=(
		const char * _Left,
		const pent_string<char>& _Right)
	{	// test if NTCS <= string
	return (!(_Right < _Left));
	}

inline bool operator<=(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// test if string <= NTCS
	return (!(_Right < _Left));
	}


inline bool operator>=(
		const pent_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string >= string
	return (!(_Left < _Right));
	}

inline bool operator>=(
		const pent_string<char>& _Left,
		const std::basic_string<char>& _Right)
	{	// test if string >= string
	return (!(_Left < _Right));
	}

inline bool operator>=(
		const std::basic_string<char>& _Left,
		const pent_string<char>& _Right)
	{	// test if string >= string
	return (!(_Left < _Right));
	}

inline bool operator>=(
		const char * _Left,
		const pent_string<char>& _Right)
	{	// test if NTCS >= string
	return (!(_Left < _Right));
	}

inline bool operator>=(
		const pent_string<char>& _Left,
		const char *_Right)
	{	// test if string >= NTCS
	return (!(_Left < _Right));
	}

#else
	typedef std::string istring;
#endif

}


#endif 

